#include "bsp_usart.h"
#include "bsp.h"

static UartHandle uart_common[3] = {0};

void UART_Init(uint8_t index, uint32_t baud, uint32_t recLen) {
    switch (index) {
    case USART1_INDEX:
        uart_common[index].huart.Instance = USART1;
        break;
    case USART2_INDEX:
        uart_common[index].huart.Instance = USART2;
        break;
    case USART3_INDEX:
        uart_common[index].huart.Instance = USART3;
        break;
    default:
        return;
    }

    uart_common[index].huart.Init.BaudRate = baud;
    uart_common[index].huart.Init.WordLength = UART_WORDLENGTH_8B;
    uart_common[index].huart.Init.StopBits = UART_STOPBITS_1;
    uart_common[index].huart.Init.Parity = UART_PARITY_NONE;
    uart_common[index].huart.Init.Mode = UART_MODE_TX_RX;
    uart_common[index].huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    uart_common[index].huart.Init.OverSampling = UART_OVERSAMPLING_16;
    uart_common[index].recBufSize = recLen;
    if (HAL_UART_Init(&uart_common[index].huart) != HAL_OK) {
        Error_Handler();
    }
}

UartHandle* GetUartHandle(uint8_t index) {
    return &uart_common[index];
}

void HAL_UART_MspInit(UART_HandleTypeDef* huart) {

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    UartHandle* pUart = NULL;
    if (huart->Instance == USART1) {
        /* USART1 clock enable */
        __HAL_RCC_USART1_CLK_ENABLE();

        __HAL_RCC_GPIOA_CLK_ENABLE();
        /**USART1 GPIO Configuration
        PA9     ------> USART1_TX
        PA10     ------> USART1_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_10;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* USART1 interrupt Init */
        pUart = &uart_common[USART1_INDEX];
        if (pUart->recBufSize) {
            HAL_NVIC_EnableIRQ(USART1_IRQn);
            HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);
        }
#ifdef ENABLE_DEBUG_SERIAL_DMA_TX
        // HAL_UART_Transmit_IT(&pUart->huart, (uint8_t*)pUart->rxTmp, 1);
        // __HAL_UART_ENABLE_IT(&pUart->huart, UART_IT_IDLE);//使能空闲中断
        __HAL_UART_ENABLE_IT(&pUart->huart, UART_IT_TC);
        #endif
    } else if (huart->Instance == USART2) {
        /* USART2 clock enable */
        __HAL_RCC_USART2_CLK_ENABLE();

        __HAL_RCC_GPIOA_CLK_ENABLE();
        /**USART2 GPIO Configuration
        PA2     ------> USART2_TX
        PA3     ------> USART2_RX
        */

        GPIO_InitStruct.Pin = GPIO_PIN_2;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_3;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* USART2 interrupt Init */
        pUart = &uart_common[USART2_INDEX];
        if (pUart->recBufSize) {
            HAL_NVIC_EnableIRQ(USART2_IRQn);
            HAL_NVIC_SetPriority(USART2_IRQn, 3, 3);
        }
    } else if (huart->Instance == USART3) {
        /* USART3 clock enable */
        __HAL_RCC_USART3_CLK_ENABLE();

        __HAL_RCC_GPIOB_CLK_ENABLE();
        /**USART3 GPIO Configuration
        PB10     ------> USART3_TX
        PB11     ------> USART3_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_10;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_11;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        /* USART3 interrupt Init */
        pUart = &uart_common[USART3_INDEX];
        if (pUart->recBufSize) {
            HAL_NVIC_EnableIRQ(USART3_IRQn);
            HAL_NVIC_SetPriority(USART3_IRQn, 3, 3);
        }
    }

    if (pUart && pUart->recBufSize) {
        pUart->buf = (uint8_t*)malloc(pUart->recBufSize);
        HAL_UART_Receive_IT(&pUart->huart, (uint8_t*)pUart->rxTmp, 1);
        __HAL_UART_ENABLE_IT(&pUart->huart, UART_IT_RXNE); // 使能RXNE中断
    }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) {

    UartHandle* pUart = NULL;
    if (huart->Instance == USART1) {
        /* Peripheral clock disable */
        __HAL_RCC_USART1_CLK_DISABLE();

        /**USART1 GPIO Configuration
        PA9     ------> USART1_TX
        PA10     ------> USART1_RX
        */
        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10);

        /* USART1 interrupt Deinit */
        HAL_NVIC_DisableIRQ(USART1_IRQn);
        pUart = &uart_common[USART1_INDEX];
    } else if (huart->Instance == USART2) {
        /* Peripheral clock disable */
        __HAL_RCC_USART2_CLK_DISABLE();

        /**USART2 GPIO Configuration
        PA2     ------> USART2_TX
        PA3     ------> USART2_RX
        */
        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2 | GPIO_PIN_3);

        /* USART2 interrupt Deinit */
        HAL_NVIC_DisableIRQ(USART2_IRQn);
        pUart = &uart_common[USART2_INDEX];
    } else if (huart->Instance == USART3) {
        /* Peripheral clock disable */
        __HAL_RCC_USART3_CLK_DISABLE();

        /**USART3 GPIO Configuration
        PC10     ------> USART3_TX
        PC11     ------> USART3_RX
        */
        HAL_GPIO_DeInit(GPIOC, GPIO_PIN_10 | GPIO_PIN_11);

        /* USART3 interrupt Deinit */
        HAL_NVIC_DisableIRQ(USART3_IRQn);
        pUart = &uart_common[USART3_INDEX];
    }

    if (pUart && pUart->recBufSize) {
        free(pUart->buf);
        __HAL_UART_DISABLE_IT(&pUart->huart, UART_IT_RXNE); // 使能RXNE中断
    }
}

/******************************************************************************************/
/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */
#if (__ARMCC_VERSION >= 6010050) || !defined(__ARMCC_VERSION) /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t");                        /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t");                          /* AC6下需要声明main函数为无参数格式，否则部分例程可能出现半主机模式 */
#else
        /* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
        #pragma import(__use_no_semihosting)

struct __FILE {
    int handle;
    /* Whatever you require here. If the only file you are using is */
    /* standard output using printf() for debugging, no file handling */
    /* is required. */
};

#endif

/* 不使用半主机模式，至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
int _ttywrch(int ch) {
    ch = ch;
    return ch;
}

/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x) {
    x = x;
}

char* _sys_command_string(char* cmd, int len) {
    return NULL;
}

/* FILE 在 stdio.h里面定义. */
FILE __stdout;

#if !defined(__ARMCC_VERSION)
int _write(int file, char* ptr, int len) {
    HAL_UART_Transmit(&uart_common[USART1_INDEX].huart, (uint8_t*)ptr, len, HAL_MAX_DELAY);
    return len;
}
#else
/* 重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE* f) {
    while ((USART1->SR & 0X40) == 0)
        ; /* 等待上一个字符发送完成 */

    USART1->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */
    return ch;
}
#endif

void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart) {
    UartHandle* pUart = NULL;
    if (huart->Instance == USART1) {
        pUart = &uart_common[USART1_INDEX];
    } else if (huart->Instance == USART2) {
        pUart = &uart_common[USART2_INDEX];
    } else if (huart->Instance == USART3) {
        pUart = &uart_common[USART3_INDEX];
        // todo 解析蓝牙模块Ack
    } else {
        return;
    }
}

#ifdef ENABLE_DEBUG_SERIAL_DMA_TX
volatile uint8_t dmaTxFlag = 1;

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1)
    {
        dmaTxFlag = 1; // 设置传输完成标志
    }
}
#endif

/**
 * @brief This function handles USART1 global interrupt.
 */
void USART1_IRQHandler(void) {
    uint32_t timeout = 0;
    uint32_t maxDelay = 0x1FFFF;

    HAL_UART_IRQHandler(&uart_common[USART1_INDEX].huart); // 调用HAL库中断处理公用函数

    timeout = 0;
    while (HAL_UART_GetState(&uart_common[USART1_INDEX].huart) != HAL_UART_STATE_READY) // 等待就绪
    {
        timeout++; ////超时处理
        if (timeout > maxDelay)
            break;
    }
    timeout = 0;
    while (HAL_UART_Receive_IT(&uart_common[USART1_INDEX].huart, (uint8_t*)uart_common[USART1_INDEX].rxTmp, 1) != HAL_OK) // 一次处理完成之后，重新开启中断并设置RxXferCount为1
    {
        timeout++; // 超时处理
        if (timeout > maxDelay)
            break;
    }
}

/**
 * @brief This function handles USART2 global interrupt.
 */
void USART2_IRQHandler(void) {
    uint32_t timeout = 0;
    uint32_t maxDelay = 0x1FFFF;

    HAL_UART_IRQHandler(&uart_common[USART2_INDEX].huart); // 调用HAL库中断处理公用函数

    timeout = 0;
    while (HAL_UART_GetState(&uart_common[USART2_INDEX].huart) != HAL_UART_STATE_READY) // 等待就绪
    {
        timeout++; ////超时处理
        if (timeout > maxDelay)
            break;
    }
    timeout = 0;
    while (HAL_UART_Receive_IT(&uart_common[USART2_INDEX].huart, (uint8_t*)uart_common[USART2_INDEX].rxTmp, 1) != HAL_OK) // 一次处理完成之后，重新开启中断并设置RxXferCount为1
    {
        timeout++; // 超时处理
        if (timeout > maxDelay)
            break;
    }
}

/**
 * @brief This function handles USART3 global interrupt.
 */
void USART3_IRQHandler(void) {
    uint32_t timeout = 0;
    uint32_t maxDelay = 0x1FFFF;

    HAL_UART_IRQHandler(&uart_common[USART3_INDEX].huart); // 调用HAL库中断处理公用函数

    timeout = 0;
    while (HAL_UART_GetState(&uart_common[USART3_INDEX].huart) != HAL_UART_STATE_READY) // 等待就绪
    {
        timeout++; ////超时处理
        if (timeout > maxDelay)
            break;
    }
    timeout = 0;
    while (HAL_UART_Receive_IT(&uart_common[USART3_INDEX].huart, (uint8_t*)uart_common[USART3_INDEX].rxTmp, 1) != HAL_OK) // 一次处理完成之后，重新开启中断并设置RxXferCount为1
    {
        timeout++; // 超时处理
        if (timeout > maxDelay)
            break;
    }
}
